package com.orange.common.handler;

import com.orange.common.exception.CustomerException;
import com.orange.common.exception.ServerException;
import com.orange.common.exception.result.CodeEnum;
import com.orange.common.exception.result.ResultSet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;

/**
 * @author : kyc
 * @Description: 全局异常处理器
 * @date : 2021-02-04 11:55
 **/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 服务名
     */
    @Value("${spring.application.name}")
    private String serverName;

    /**
     * 错误信息前缀
     */
    private String errorMessagePrefix;

    @PostConstruct
    public void init() {
        this.errorMessagePrefix = "(" + this.serverName + "服务->)";

    }

    /**
     * 处理系统内部异常(未知异常,空指针,索引越界)
     * @return 异常结果集
     */
    @ExceptionHandler(value = {Exception.class})
    public ResultSet handlerException(Exception e, HttpServletRequest request){
        log.error("请求路径uri={},系统内部出现异常:{}",request.getRequestURI(),e);
        ResultSet resultSet = ResultSet.error(CodeEnum.SYSTEM_INNER_ERROR,errorMessagePrefix+e.toString(),"服务器繁忙,请稍后再试");
        return resultSet;
    }

    /**
     * 非法请求异常(SpringAop)
     * @return 异常结果集
     */
    @ExceptionHandler(value = {
            HttpMediaTypeNotAcceptableException.class,
            HttpMediaTypeNotSupportedException.class,
            HttpRequestMethodNotSupportedException.class,
            MissingServletRequestParameterException.class,
            NoHandlerFoundException.class,
            MissingPathVariableException.class,
            HttpMessageNotReadableException.class
    })
    public ResultSet handlerSpringAopException(Exception exception){
        ResultSet resultSet= ResultSet.error(CodeEnum.ILLEGAL_REQUEST,errorMessagePrefix+exception.getMessage(),exception.getMessage());
        return resultSet;
    }

    /**
     * 非法请求异常(@DateTimeFormat注解抛出异常)
     * @return 异常结果集
     */
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    public ResultSet handlerSpringAOPException(MethodArgumentTypeMismatchException e) {
        ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix+e.getMessage(),e.getMessage());
        return resultSet;
    }

    /**
     * 非法请求异常(处理spring validation参数校验抛出异常1)
     * @return 异常结果集
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResultSet handlerMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
        //获取异常字段及对应的异常信息
        StringBuffer stringBuffer = new StringBuffer();
        methodArgumentNotValidException.getBindingResult().getFieldErrors().stream()
                .map(t -> t.getField()+"=>"+t.getDefaultMessage()+" ")
                .forEach(e -> stringBuffer.append(e));
        String errorMessage = stringBuffer.toString();
        ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix+errorMessage,errorMessage);
        return resultSet;
    }

    /**
     * 非法请求异常(处理spring validation参数校验抛出异常2)
     * @return 异常结果集
     */
    @ExceptionHandler(value = {ConstraintViolationException.class})
    public ResultSet handlerConstraintViolationException(ConstraintViolationException constraintViolationException) {
        String errorMessage = constraintViolationException.getLocalizedMessage();
        ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST,errorMessagePrefix+errorMessage,errorMessage);
        return resultSet;
    }

    /**
     * 处理自定义异常-CustomException
     * @return 异常结果集
     */
    @ExceptionHandler(value = {CustomerException.class})
    public ResultSet handlerCustomException(CustomerException e) {
        String errorMessage = e.getErrorMessage();
        ResultSet resultSet = ResultSet.error(e.getCodeEnum(), errorMessagePrefix+errorMessage,errorMessage);
        return resultSet;
    }

    /**
     * 处理自定义异常-ServerException
     * @return 异常结果集
     */
    @ExceptionHandler(value = {ServerException.class})
    public ResultSet handlerServerException(ServerException e) {
        String errorMessage = e.getErrorMessage();
        ResultSet resultSet = ResultSet.error(e.getCodeEnum(), errorMessagePrefix+errorMessage,errorMessage);
        return resultSet;
    }

}
